<?php

namespace App\Manage;


use App\Models\AdminRole;
use App\Models\Goods;
use App\Models\GoodsCate;
use App\Service\Tree;
use Illuminate\Database\Eloquent\Casts\Attribute;

class GoodsCateManage extends Manage
{


    // 修改

    // TODO 操作日志

    // 父级
    // 添加，修改，删除，列表，停用 操作


    // 模型
    protected function getModel()
    {
        return new GoodsCate();
    }

    // 列表
    public function lists($myUser, $options = [])
    {

        // 参数
        $is_admin_log = $options['is_admin_log'] ?? 0;


        $opt  = $this->option();
        $page = $opt->getData('page', 1, 'intval');
        $rows = $opt->getData('rows', 15, 'intval');

        list($cache, $where) = $this->listWhere();
        // 查询
        $model  = new GoodsCate();
        $result = $model->listPageCache($cache, $where, $page, $rows, 'rank ASC');
        if($result === false){
            return $this->_returnFail($model->getError());
        }

        return $result;
    }

    // 树状
    public function tree($myUser, $options = [])
    {

        // 参数
        $is_admin_log = $options['is_admin_log'] ?? 0;


        $opt       = $this->option();
        $initKey   = $opt->getData("initKey", 'id', 'trim');
        $isTree    = $opt->getData('isTree', 0, 'intval');   // Build-Admin 展示树状列表
        $page      = $opt->getData('page', 1, 'intval');
        $rows      = $opt->getData('rows', 15, 'intval');
        $initValue = $opt->getData('initValue', 0, 'intval');
        $keyword   = $opt->getData("quickSearch", '', 'trim');
        $isBuild   = $opt->getHeader('Build-Admin', 0, 'intval');   // Build-Admin
        //$initValue = array_filter($initValue);

        $where = [['status', '=', 1]];
        if($keyword){
            $keyword = explode(' ', $$keyword);
            foreach($keyword as $item){
                $where[] = ['name', 'like', '%'.$item.'%'];
            }
        }
        if($initValue){
            $where[] = [$initKey, 'in', $initValue];
        }


        list($cache, $where) = $this->listWhere();

        // 树状制作
        $model = new GoodsCate();
        $lists = $model->getListCache($cache, $where, 0, 'rank ASC');
        if($lists === false){
            return $this->_returnFail($model->getError());
        }


        if(!empty($lists)){
            $tree = new Tree();
            // Build-Admin 下拉筛选框使用
            if($isTree && $isBuild){
                $lists = $tree->toList($lists); // 树状
                foreach($lists as &$item){
                    $item['title'] = str_repeat('  ', $item['level']).'└'.$item['title'];
                    //$item['title'] = str_repeat(str_pad('  ', 4), $item['level']).'└'.$item['title'];
                }
            } else{
                $lists = $tree->toTree($lists); // 树状
            }
        }

        // Build-Admin 下拉筛选框使用
        // 其他情况，和原本的一致
        if($isBuild && $isTree){
            return ['options' => $lists];
        }

        $total  = count($lists);
        $result = ['total' => $total, 'page' => 1, 'rows' => $rows, 'list' => $lists,];

        return $result;
    }


    public function _select()
    {

        $model = new AdminRole();
        $where = [['status', '=', 1]];
        $opt   = $this->option();

        $initKey   = $opt->getData("initKey", 'id', 'trim');
        $isTree    = $opt->getData('isTree', true);
        $page      = $opt->getData('page', 1, 'intval');
        $rows      = $opt->getData('rows', 15, 'intval');
        $initValue = $opt->getData('initValue', 0, 'intval');

        // 下拉选择时只获取：拥有所有权限并且有额外权限的分组
        $absoluteAuth = $opt->getData('absoluteAuth/b', false);
        $keyword      = $opt->getData("quickSearch", '');

        if($keyword){
            $keyword = explode(' ', $$keyword);
            foreach($keyword as $item){
                $where[] = ['name', 'like', '%'.$item.'%'];
            }
        }

        $initValue = $opt->getData("initValue/a", []);
        $initValue = array_filter($initValue);
        if($initValue){
            $where[] = [$initKey, 'in', $initValue];
        }


        $data = $model->where($where)->select()->toArray();
        $tree = new Tree();
        $data = $tree->toTree($data); // 树状

        $isBuild = $opt->getHeader('Build-Admin', 0, 'intval');
        if($isBuild){
            return ['options' => $data];
        }

        return $data;


        // 获取第一个权限的名称供列表显示-e

        // 如果要求树状，此处先组装好 children
        /*$data = $this->assembleChild($data);

        $assembleTree = $isTree && !$initValue;
        if ($assembleTree) {
            $data = $this->assembleTree($this->getTreeArray($data));
        }

        return  $this->success([
            'options' => $data
        ]);*/
    }


    // 详情
    public function show($myUser, $options = [])
    {
        $opt = $this->option();
        $id  = $opt->getData('id', 0, 'intval');
        if(empty($id)){
            //return $this->_returnFail('请指定查看记录');
            return $this->_returnFail('select_operation_id');
        }


        // 参数
        $is_admin_log = $options['is_admin_log'] ?? 0;
        $isBuild      = $opt->getHeader('Build-Admin', 0, 'intval');


        $where = ['id' => $id];
        $model = new GoodsCate();
        $info  = $model->oneFindCache($where, $where);
        if($info === false){
            return $this->_returnFail($model->getError());
        }

        // 数据整理
        // $info['image'] = $this->getFullUrl($info['image']);

        // 如果是build-admin
        if($isBuild){
            return ['row' => $info];
        }

        return $info;
    }

    // 排序
    public function rank($myUser, $options = [])
    {
        $opt  = $this->option();
        $id   = $opt->getData('id', 0, 'intval');
        $rank = $opt->getData('rank', 0, 'intval');
        if(empty($id)){
            //return $this->_returnFail('请指定查看记录');
            return $this->_returnFail('select_operation_id');
        }
        if(is_null($rank)){
            //return $this->_returnFail('请填写排序数字！！');
            return $this->_returnFail('fill_in_the_sorting_number');
        }


        // 参数
        $is_admin_log = $options['is_admin_log'] ?? 0;


        // 执行
        $model  = new GoodsCate();
        $result = $model->oneEdit(['id' => $id], ['rank' => $rank]);
        if($result === false){
            return $this->_returnFail($model->getError());
        }


        // 管理员日志
        /*if($is_admin_log){
            $this->addAdminLog($myUser['id'], '修改自己的个人资料', '');
        }*/


        return true;
    }


    // 启用禁用
    public function status($myUser, $options = [])
    {
        $opt    = $this->option();
        $id     = $opt->getData('id', 0, 'intval');
        $_value = $opt->getData('status', 0, 'intval');
        if(empty($id)){
            //return $this->_returnFail('请指定查看记录');
            return $this->_returnFail('select_operation_id');
        }
        if(is_null($_value)){
            return $this->_returnFail('enable_disable_status_must_be_filled');
        }
        if(!in_array($_value, [0, 1])){
            return $this->_returnFail('status_value_must_be_0_1');
        }

        // 参数
        $is_admin_log = $options['is_admin_log'] ?? 0;


        // 执行
        $model  = new GoodsCate();
        $result = $model->oneEdit(['id' => $id], ['status' => $_value]);
        if($result === false){
            return $this->_returnFail($model->getError());
        }


        // 管理员日志
        /*if($is_admin_log){
            $this->addAdminLog($myUser['id'], '修改自己的个人资料', '');
        }*/


        return true;
    }

    // 删除（软删除）
    public function del($myUser, $options = [])
    {
        $opt = $this->option();
        $id  = $opt->getData('id', 0, 'intval');
        $ids = $opt->getData('ids', [], 'is_array');
        // 修改记录
        if(empty($id) && empty($ids)){
            //return $this->_returnFail('请指定删除记录！');
            return $this->_returnFail('select_operation_id');
        }


        // 参数
        $is_admin_log = $options['is_admin_log'] ?? 0;


        // 查找是否有商品
        $goodsDb = new Goods();

        // 查询商品条件
        $gwhere = [];
        if($id){
            $where[] = ['cate_id', '=', $id];
        }
        if($ids){
            $where[] = function($qq) use ($ids) {
                $qq = $qq->whereIn('cate_id', $ids);
            };
        }

        // 查询
        $goods = $goodsDb->where($gwhere)->get()->toArray();
        if($goods){
            //return $this->_returnFail('该分类下面还有商品，您不能删除！');
            return $this->_returnFail('category_has_products_cannot_delete_it');
        }

        // 删除的时候：如果有子级不能删除
        $model = new GoodsCate();
        if($id){
            $_ids = $model->getChildIds($id);
            if($_ids){
                //return $this->_returnFail('有子级不能被删除!');
                return $this->_returnFail('parent_with_child_item_cannot_be_delete');
            }
        }
        if($ids){
            foreach($ids as $_id){
                $_ids = $model->getChildIds($_id);
                if($_ids){
                    //return $this->_returnFail('有子级不能被删除!');
                    return $this->_returnFail('parent_with_child_item_cannot_be_delete');
                }
            }
        }

        // 条件
        $where = [];
        if($id){
            $where[] = ['id', '=', $id];
        }
        if($ids){
            $where[] = [
                function($qq) use ($ids) {
                    $qq = $qq->whereIn('id', $ids);
                },
            ];
        }

        // 查询
        $lists = $model->newQuery()->where($where)->get()->toArray();;  //->recycle()
        if(empty($lists)){
            return $this->_returnFail('data_delete_has_not_exist');
            //return $this->_returnFail('你要删除的数据不存在！！');
        }

        // 缓存操作
        $model->deleteCacheList($lists);

        // 删除
        $res = $model->where($where)->delete();

        // 管理员日志
        if($is_admin_log){
            //$this->addAdminLog($myUser['id'], '删除商品分类');
        }

        return true;
    }

    // 列表查询
    protected function listWhere()
    {
        $opt     = $this->option();
        $where   = [['status', '=', 1]];
        $cache   = ['status' => 1];
        $keyword = $opt->getData('keyword', null, 'trim');
        if($keyword){
            $cache   = false;
            $where[] = $opt->orWhere('name|describe', 'like', $keyword);
        }

        return [$cache, $where];
    }

    // 添加
    protected function _before_add()
    {

        // 参数
        $is_admin_log = $options['is_admin_log'] ?? 0;


        $opt  = $this->option();
        $data = [
            'status'      => $opt->getData("status", 1, 'intval'),
            'is_propose'  => $opt->getData("is_propose", 0, 'intval'),
            'keyword'     => $opt->getData("keyword", null, 'trim'),
            'description' => $opt->getData("description", null, 'trim'),
            'pid'         => $opt->getData('pid', 0, 'intval'),
            'title'       => $opt->getData('title', null, 'trim'),
            'pic'         => $opt->getData('pic', null, 'trim'),
            'rank'        => $opt->getData('rank', 0, 'intval'),
        ];

        // 设置pic
        if($data['pic']){
            $model = new GoodsCate();
            // 设置
            $data['pic'] = $model->setPicAttribute($data['pic']);
        }

        // 管理员日志
        /*if($is_admin_log){
            $this->addAdminLog($myUser['id'], '修改自己的个人资料', '');
        }*/


        return $data;
    }

    // 修改
    protected function _before_edit()
    {
        $opt = $this->option();
        $id  = $opt->getData('id', 0, 'intval');
        if(empty($id)){
            //return $this->_returnFail('请指定查看记录！');
            return $this->_returnFail('select_operation_id');
        }


        // 参数
        $is_admin_log = $options['is_admin_log'] ?? 0;


        $data = [
            'status'      => $opt->getData("status", 1, 'intval'),
            'is_propose'  => $opt->getData("is_propose", 0, 'intval'),
            'keyword'     => $opt->getData("keyword", null, 'trim'),
            'description' => $opt->getData("description", null, 'trim'),
            'pid'         => $opt->getData('pid', 0, 'intval'),
            'title'       => $opt->getData('title', null, 'trim'),
            'pic'         => $opt->getData('pic', null, 'trim'),
            'rank'        => $opt->getData('rank', 0, 'intval'),
        ];

        // 修改的时候：如果有父级 则父级不能是当前id 也不能是当前id的子级
        if(!empty($data['pid'])){
            $pid = $data['pid'];
            if($id == $pid){
                return $this->_returnFail('parent_cannot_be_set_to_itself');
                //return $this->_returnFail('修改父级不能是自己！');
            }

            // 获取当前的子级
            $cateDb = new GoodsCate();
            $ids    = $cateDb->getChildIds($id);
            if($ids && in_array($pid, $ids)){
                //return $this->_returnFail('修改父级不能是自己的子级！');
                return $this->_returnFail('parent_cannot_be_set_to_itself_own_child');
            }
        }

        // 设置pic
        if($data['pic']){
            $model = new GoodsCate();
            // 设置
            $data['pic'] = $model->setPicAttribute($data['pic']);
        }

        // 管理员日志
        /*if($is_admin_log){
            $this->addAdminLog($myUser['id'], '修改自己的个人资料', '');
        }*/


        return $data;
    }

    ############################################################################

    /**
     * 递归的根据指定字段组装 children 数组
     * @param array $data 数据源 例如：[['id' => 1, 'pid' => 0, title => '标题1'], ['id' => 2, 'pid' => 1, title => '标题1-1']]
     * @param string $pid 存储上级id的字段
     * @param string $pk 主键字段
     * @return array ['id' => 1, 'pid' => 0, 'title' => '标题1', 'children' => ['id' => 2, 'pid' => 1, 'title' => '标题1-1']]
     */
    public function assembleChild(array $data, string $pid = 'pid', string $pk = 'id'):array
    {
        if(!$data) return [];

        $pks            = [];
        $topLevelData   = []; // 顶级数据
        $this->children = []; // 置空子级数据
        foreach($data as $item){
            $pks[] = $item[$pk];

            // 以pid组成children
            $this->children[$item[$pid]][] = $item;
        }
        // 上级不存在的就是顶级，只获取它们的 children
        foreach($data as $item){
            if(!in_array($item[$pid], $pks)){
                $topLevelData[] = $item;
            }
        }

        if(count($this->children) > 0){
            foreach($topLevelData as $key => $item){
                $topLevelData[$key]['children'] = $this->getChildren($this->children[$item[$pk]] ?? [], $pk);
            }

            return $topLevelData;
        } else{
            return $data;
        }
    }

    /**
     * 将数组某个字段渲染为树状,需自备children children可通过$this->assembleChild()方法组装
     * @param array $arr 要改为树状的数组
     * @param string $field '树枝'字段
     * @param int $level 递归数组层次,无需手动维护
     * @param bool $superiorEnd 递归上一级树枝是否结束,无需手动维护
     * @return array
     */
    public static function getTreeArray(array $arr, string $field = 'name', int $level = 0, bool $superiorEnd = false):array
    {
        $level++;
        $number = 1;
        $total  = count($arr);
        foreach($arr as $key => $item){
            $prefix = ($number == $total) ? self::$icon[2] : self::$icon[1];
            if($level == 2){
                $arr[$key][$field] = str_pad('', 4).$prefix.$item[$field];
            } elseif($level >= 3){
                $arr[$key][$field] = str_pad('', 4).($superiorEnd ? '' : self::$icon[0]).str_pad('', ($level - 2) * 4).$prefix.$item[$field];
            }

            if(isset($item['children']) && $item['children']){
                $arr[$key]['children'] = self::getTreeArray($item['children'], $field, $level, $number == $total);
            }
            $number++;
        }

        return $arr;
    }

    /**
     * 递归合并树状数组（根据children多维变二维方便渲染）
     * @param array $data 要合并的数组 ['id' => 1, 'pid' => 0, 'title' => '标题1', 'children' => ['id' => 2, 'pid' => 1, 'title' => '    └标题1-1']]
     * @return array [['id' => 1, 'pid' => 0, 'title' => '标题1'], ['id' => 2, 'pid' => 1, 'title' => '    └标题1-1']]
     */
    public static function assembleTree(array $data):array
    {
        $arr = [];
        foreach($data as $v){
            $children = $v['children'] ?? [];
            unset($v['children']);
            $arr[] = $v;
            if($children){
                $arr = array_merge($arr, self::assembleTree($children));
            }
        }

        return $arr;
    }

    /**
     * 获取 children 数组
     * 辅助 assembleChild 组装 children
     * @param array $data
     * @param string $pk
     * @return array
     */
    protected function getChildren(array $data, string $pk = 'id'):array
    {
        if(!$data) return [];
        foreach($data as $key => $item){
            if(array_key_exists($item[$pk], $this->children)){
                $data[$key]['children'] = $this->getChildren($this->children[$item[$pk]], $pk);
            }
        }

        return $data;
    }

}

